﻿// IOCPServer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"

#include "Global.h"

#include <vector>
#include <list>

#include <array>
#include <thread>

//typedef unsigned(__stdcall* _beginthreadex_proc_type)(void*);

unsigned __stdcall _worker(void* context)
{
    IO_DATA *lpIOContext = NULL;
    BOOL bTrue = FALSE;
    DWORD dwTimeout = INFINITE;
    DWORD dwFlags = 0;
    DWORD nBytes = 0;
    DWORD dwIoSize = 0;
    int nRet = 0;
    ULONG_PTR lpCompletionKey = NULL;
    LPOVERLAPPED lpOverlapped = NULL;
    int lastSystemError = 0;
    

    while (true)
    {
        if (g.hIocp != NULL) {
            Sleep(55);
            continue;
        }

        bTrue = GetQueuedCompletionStatus(g.hIocp, &dwIoSize, &lpCompletionKey, &lpOverlapped, dwTimeout);
        if (!bTrue) {
            break;
        }
        //lpIOContext = static_cast<IO_DATA*>((void*)lpOverlapped); // 这个貌似 是从 【void *】 转换成 【SomeType *】
        //lpIOContext = dynamic_cast<IO_DATA*>(lpOverlapped);// 这个要求 操作数必须是多态类型
        lpIOContext = reinterpret_cast<IO_DATA*>(lpOverlapped);
        if (dwIoSize == 0) {
            std::cout << "Client disconnected.\n";

            closesocket(lpIOContext->socket);
            lpIOContext->socket = INVALID_SOCKET;
            delete lpIOContext;
            continue;
        }

        if (IO_READ == lpIOContext->op) {
            
            nBytes = strlen(g.buffer) + 1;
            lpIOContext->wsaBuf.len = nBytes;
            lpIOContext->wsaBuf.buf = g.buffer;
            lpIOContext->op = IO_WRITE;
            lpIOContext->size = nBytes;
            dwFlags = 0;

            memset(&lpIOContext->overlapped, 0, sizeof(lpIOContext->overlapped));

            nRet = WSASend(lpIOContext->socket, &lpIOContext->wsaBuf, 1, &nBytes, dwFlags, &lpIOContext->overlapped, NULL);
            lastSystemError = WSAGetLastError();
            if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != lastSystemError)) {
                std::cout << "WSASend fails, WSAGetLastError()=" << lastSystemError << std::endl;
                closesocket(lpIOContext->socket);
                delete lpIOContext;
                continue;
            }

            memset(g.buffer, 0, sizeof(g.buffer));
        }
        else if (IO_WRITE == lpIOContext->op) {
            lpIOContext->op = IO_READ;
            nBytes = sizeof(g.buffer);
            dwFlags = 0;
            lpIOContext->wsaBuf.buf = g.buffer;
            lpIOContext->wsaBuf.len = nBytes;
            lpIOContext->size = nBytes;

            memset(&lpIOContext->overlapped, 0, sizeof(lpIOContext->overlapped));

            nRet = WSARecv(lpIOContext->socket, &lpIOContext->wsaBuf, 1, &nBytes, &dwFlags, &lpIOContext->overlapped, NULL);
            lastSystemError = WSAGetLastError();
            if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != lastSystemError)) {
                std::cout << "WSARecv fails, WSAGetLastError()=" << lastSystemError << std::endl;
                closesocket(lpIOContext->socket);
                delete lpIOContext;
                continue;
            }

            std::cout << lpIOContext->wsaBuf.buf << std::endl;
        }
        else {
            std::cout << "Unknown operation [ " << lpIOContext->op << " ]." << std::endl;
            continue;
        }
        
    }

    return 0;
}

int GetNeededThreadCount()
{
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    unsigned int cnt = std::thread::hardware_concurrency();
    return (sysInfo.dwNumberOfProcessors * 2);
}

void WSAOverlapped_Completion_Routine(
    IN DWORD dwError,
    IN DWORD cbTransferred,
    IN LPWSAOVERLAPPED lpOverlapped,
    IN DWORD dwFlags
)
{
    //
}

int main(int argc, char* argv[])
{
    int ret = 0;
    int lastSystemError = 0;
    WSADATA wsaData;
    sockaddr_in socksrv;
    int threadcount = GetNeededThreadCount();

    std::vector<HANDLE> vHandle;
    std::list<HANDLE> lHandle;

    std::array<HANDLE, 100> arrHandle;
    int thrdCnt = 0; // 线程实际的个数

    WSAStartup(MAKEWORD(2, 2), &wsaData);

    do
    {
        SOCKET socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
        if (INVALID_SOCKET == socket) {
            lastSystemError = WSAGetLastError();
            std::cout << "WSARecv fails, WSAGetLastError()=" << lastSystemError << std::endl;
            break;
        }

        socksrv.sin_family = AF_INET;
        socksrv.sin_port = htons(56789);
        socksrv.sin_addr.S_un.S_addr = htonl(ADDR_ANY);

        ret = bind(socket, (sockaddr*)&socksrv, sizeof(socksrv));

        ret = listen(socket, 10);

        g.hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, threadcount);
        if (NULL == g.hIocp) {
            lastSystemError = GetLastError();
            std::cout << "CreateIoCompletionPort fails, GetLastError()=" << lastSystemError << std::endl;
            break;
        }

        
        thrdCnt = 0;

        for (int i = 0; i < threadcount; i++)
        {
            HANDLE hThread = NULL;
            unsigned int threadId = 0;

            hThread = (HANDLE)_beginthreadex(NULL, 0, _worker, NULL, 0, &threadId);
            if (hThread != NULL) {
                arrHandle[thrdCnt] = hThread;
                thrdCnt++;
            }
        }

        while (true)
        {
            sockaddr_in _in;
            int siz = (int)sizeof(_in);
            //SOCKET client = accept(socket, (sockaddr*)&_in, &siz);
            SOCKET client = accept(socket, NULL, NULL);
            if (client == INVALID_SOCKET) {
                Sleep(55);
                continue;
            }

            HANDLE hIOCP = CreateIoCompletionPort((HANDLE)client, g.hIocp, 0, 0);
            if (NULL == hIOCP) {
                lastSystemError = GetLastError();
                std::cout << "After accept, CreateIoCompletionPort fails, GetLastError()=" << lastSystemError << std::endl;
                closesocket(client);
                continue;
            }

            IO_DATA *data = new IO_DATA;
            //memset(g.buffer, 0, sizeof(g.buffer));
            memset(&data->overlapped, 0, sizeof(data->overlapped));

            data->op = IO_READ;
            data->size = 0;
            data->wsaBuf.buf = g.buffer;
            data->wsaBuf.len = sizeof(g.buffer);
            data->socket = client;

            DWORD nBytes = sizeof(g.buffer);
            DWORD dwFlags = 0;

            int iRet = WSARecv(client, &data->wsaBuf, 1, &nBytes, &dwFlags, &data->overlapped, NULL);
            lastSystemError = WSAGetLastError();
            if (iRet == SOCKET_ERROR && (ERROR_IO_PENDING != lastSystemError)) {
                std::cout << "WSARecv fails, WSAGetLastError()=" << lastSystemError << std::endl;
                closesocket(client);
                delete data;
                continue;
            }

            if (ERROR_IO_PENDING == lastSystemError)
            {
                // 等待 IO 完成
                std::cout << "Wait Pending IO....." << std::endl;
            }
            else if (ERROR_IO_PENDING != lastSystemError)
            {
                std::cout << data->wsaBuf.buf << std::endl;
            }

            

        }

    } while (false);

    if (thrdCnt > 0) {
        for (int i = 0; i < thrdCnt; i++)
        {
            if (arrHandle[i] != NULL)
                CloseHandle(arrHandle[i]);
            arrHandle[i] = NULL;
        }
    }
    
    if (g.hIocp != NULL) {
        CloseHandle(g.hIocp);
        g.hIocp = NULL;
    }

    

    return ret;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门提示: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
